#include "option.h"

// Qt Includes
#include <QDomElement>

// Globals
const QString gc_astrOptionTypeNames[] =
{
    QObject::tr("Unknown"),
    QObject::tr("String"),
    QObject::tr("Bool"),
    QObject::tr("Int"),
    QObject::tr("StringList")
};

// ------------------------------------------------------------------
// Construction & Destruction
// ------------------------------------------------------------------
COption::COption(tOptionType optionType, const QString &strDescription, const QVariant &vValue)
    : m_tType(optionType),
      m_strDescription(strDescription),
      m_vValue(vValue)
{
    Q_ASSERT(optionType != OPTION_TYPE_UNKNOWN);
}

COption::COption()
    : m_tType(OPTION_TYPE_UNKNOWN)
{

}

// ------------------------------------------------------------------
// Member Functions
// ------------------------------------------------------------------
bool COption::saveOption(QDomDocument &domDocument, QDomElement &domElement) const
{
    if(domElement.isNull())
	return false;

    if(m_tType == OPTION_TYPE_UNKNOWN)
	return false;

    QDomElement domOptionType = domDocument.createElement(QObject::tr("type"));
    QDomElement domOptionDescription = domDocument.createElement(QObject::tr("description"));
    QDomElement domOptionValue = domDocument.createElement(QObject::tr("value"));

    domOptionType.appendChild(domDocument.createTextNode(gc_astrOptionTypeNames[m_tType]));
    domOptionDescription.appendChild(domDocument.createTextNode(m_strDescription));
    domOptionValue.appendChild(domDocument.createTextNode(m_vValue.toString()));

    domElement.appendChild(domOptionType);
    domElement.appendChild(domOptionDescription);
    domElement.appendChild(domOptionValue);

    return true;
}

bool COption::loadOption(const QDomElement &domElement)
{
    if(domElement.isNull())
	return false;

    if(!domElement.hasChildNodes())
	return false;

    bool bTypeFound = false, bDescriptionFound = false, bValueFound = false;
    tOptionType tType = OPTION_TYPE_UNKNOWN;
    QString strOptionValue, strOptionDescription;

    QDomNodeList domChildNodeList = domElement.childNodes();
    const int nChildNodeCount = domChildNodeList.count();

    for(int i = 0; i < nChildNodeCount; i++)
    {
	QDomNode domChildNode = domChildNodeList.at(i);

	if(domChildNode.isNull())
	    continue;

	if(domChildNode.nodeType() != QDomNode::ElementNode)
	    continue;

	const QString strNodeName = domChildNode.nodeName();

	if(strNodeName == QObject::tr("type"))
	{
	    domChildNode = domChildNode.firstChild();

	    if(domChildNode.nodeType() == QDomNode::TextNode)
	    {
		tType = getOptionType(domChildNode.nodeValue());
		bTypeFound = true;
	    }
	}
	else if(strNodeName == QObject::tr("description"))
	{
	    domChildNode = domChildNode.firstChild();

	    if(domChildNode.nodeType() == QDomNode::TextNode)
	    {
		strOptionDescription = domChildNode.nodeValue();
		bDescriptionFound = true;
	    }
	}
	else if(strNodeName == QObject::tr("value"))
	{
	    domChildNode = domChildNode.firstChild();

	    if(domChildNode.nodeType() == QDomNode::TextNode)
	    {
		strOptionValue = domChildNode.nodeValue();
		bValueFound = true;
	    }
	}
    }

    // We must have all three nodes for this to be valid.
    if(!bTypeFound || !bDescriptionFound || !bValueFound)
	return false;

    m_tType = tType;
    m_strDescription = strOptionDescription;
    m_vValue = getOptionValue(strOptionValue, tType);

    return true;
}

// ------------------------------------------------------------------
// Static Member Functions
// ------------------------------------------------------------------
COption::tOptionType COption::getOptionType(const QString &strOptionType)
{
    static QMap<QString, tOptionType> mapOptionTypes;

    if(mapOptionTypes.count() == 0)
    {
	mapOptionTypes.insert(gc_astrOptionTypeNames[OPTION_TYPE_UNKNOWN], OPTION_TYPE_UNKNOWN);
	mapOptionTypes.insert(gc_astrOptionTypeNames[OPTION_TYPE_STRING], OPTION_TYPE_STRING);
	mapOptionTypes.insert(gc_astrOptionTypeNames[OPTION_TYPE_BOOL], OPTION_TYPE_BOOL);
	mapOptionTypes.insert(gc_astrOptionTypeNames[OPTION_TYPE_INT], OPTION_TYPE_INT);
	mapOptionTypes.insert(gc_astrOptionTypeNames[OPTION_TYPE_STRINGLIST], OPTION_TYPE_STRINGLIST);
    }

    return mapOptionTypes.value(strOptionType, OPTION_TYPE_UNKNOWN);
}

QVariant COption::getOptionValue(const QString &strOptionValue, COption::tOptionType tType)
{
    switch(tType)
    {
	default:
	case OPTION_TYPE_UNKNOWN:
	    return QVariant();

	case OPTION_TYPE_STRING:
	    return strOptionValue;

	case OPTION_TYPE_BOOL:
	    return ((strOptionValue == "true") ? true: false);

	case OPTION_TYPE_INT:
	    return strOptionValue.toInt();

	case OPTION_TYPE_STRINGLIST:
	    return QVariant(); // TODO: How do we manage a string-list?
    }
}
